﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using Microsoft.VisualStudio.ProjectSystem;
using Microsoft.VisualStudio.ProjectSystem.Debug;
using Microsoft.VisualStudio.ProjectSystem.Properties;
using Microsoft.VisualStudio.ProjectSystem.VS.Debug;

namespace Red.Scripts.Project.Debugger
{
    [ExportDebugger( RedScriptsDebugger.SchemaName )]
    [AppliesTo( MyUnconfiguredProject.UniqueCapability )]
    public class LaunchProvider : DebugLaunchProviderBase
    {
        #region Private Data

        // TODO: Specify the assembly full name here
        [ExportPropertyXamlRuleDefinition( "Red.Scripts.Project, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9be6e469bc4921f1", "XamlRuleToCode:RedScriptsDebugger.xaml", "Project" )]
        [AppliesTo( MyUnconfiguredProject.UniqueCapability )]
        private object DebuggerXaml { get { throw new NotImplementedException(); } }

        #endregion Private Data

        #region Imports

        /// <summary>
        /// Gets project properties that the debugger needs to launch.
        /// </summary>
        [Import]
        private ProjectProperties ProjectProperties { get; set; }

        #endregion Imports

        #region C-Tor

        [ImportingConstructor]
        public LaunchProvider( ConfiguredProject configuredProject )
            : base( configuredProject )
        {
        }

        #endregion C-Tor

        #region Private Methods

        private async Task<string> GetArgumentBool( IEvaluatedProperty property )
        {
            if ( property.IncludeInCommandLine && (bool)await property.GetValueAsync() )
            {
                return $"{property.SwitchPrefix}{property.Switch} ";
            }

            return string.Empty;
        }

        private async Task<string> GetArgument( IEvaluatedProperty property )
        {
            if ( property.IncludeInCommandLine )
            {
                string value = await property.GetEvaluatedValueAtEndAsync();

                if ( !string.IsNullOrWhiteSpace( value ) )
                {
                    return $"{property.SwitchPrefix}{property.Switch}=\"{value}\" ";
                }
            }

            return string.Empty;
        }

        #endregion Private Methods

        #region DebugLaunchProviderBase

        public override Task LaunchAsync( DebugLaunchOptions launchOptions )
        {
            Task task = base.LaunchAsync( launchOptions );

            return task;
        }

        public override async Task<bool> CanLaunchAsync( DebugLaunchOptions launchOptions )
        {
            await Task.CompletedTask;

            return true;
        }

        public override async Task<IReadOnlyList<IDebugLaunchSettings>> QueryDebugTargetsAsync( DebugLaunchOptions launchOptions )
        {
            var settings = new DebugLaunchSettings( launchOptions );

            Utility.DefinesAccessor defines = new Utility.DefinesAccessor();
            await defines.Load();

            // The properties that are available via DebuggerProperties are determined by the property XAML files in your project.
            var debuggerProperties = await ProjectProperties.GetRedScriptsDebuggerPropertiesAsync();

            settings.Executable = await debuggerProperties.RedScriptsPathToLauncher.GetEvaluatedValueAtEndAsync();
            settings.CurrentDirectory = await debuggerProperties.RedScriptsCWD.GetEvaluatedValueAtEndAsync();
            settings.Arguments = await Utility.CommandlineBuilder.ConstructLaunch( ProjectProperties, defines );
            settings.LaunchOperation = DebugLaunchOperation.CreateProcess;
            settings.LaunchDebugEngineGuid = defines.EngineGuid;
            settings.PortSupplierGuid = defines.PortSupplierGuid;

            if ( settings.Executable == @"<Automatic>" )
            {
                settings.Executable = defines.Locate( "launcher.exe" );
            }

            if ( settings.CurrentDirectory == @"<ExecutableDirectory>" )
            {
                settings.CurrentDirectory = System.IO.Path.GetDirectoryName( settings.Executable );
            }

            return new IDebugLaunchSettings[] { settings };
        }

        #endregion DebugLaunchProviderBase
    }
}
